1 /*
2  *  libdvbv5-d — a D binding to the libdvbv5 library.
3  *
4  *  Copyright © 2018, 2019  Russel Winder
5  *
6  *  This program is free software: you can redistribute it and/or modify
7  *  it under the terms of the GNU Lesser General Public License as published by
8  *  the Free Software Foundation, either version 3 of the License, or
9  *  (at your option) any later version.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  *  GNU Lesser General Public License for more details.
15  *
16  *  You should have received a copy of the GNU Lesser General Public License
17  *  along with this program. If not, see <http://www.gnu.org/licenses/>.
18  */
19 
20 module libdvbv5_d.types;
21 
22 import std.exception: enforce;
23 import std.string: toStringz;
24 
25 import libdvbv5_d.dvb_demux: dvb_dmx_open, dvb_dmx_close;
26 import libdvbv5_d.dvb_fe: dvb_v5_fe_parms, dvb_fe_open, dvb_fe_close;
27 import libdvbv5_d.dvb_frontend: fe_delivery_system;
28 import libdvbv5_d.dvb_file: dvb_file, dvb_entry, dvb_file_free, dvb_file_formats, dvb_read_file_format;
29 import libdvbv5_d.dvb_scan: dvb_v5_descriptors, check_frontend_t, dvb_scan_transponder, dvb_scan_free_handler_table;
30 
31 /**
32  * A pair (adapter_number, frontend_number) to uniquely identify the frontends
33  * available at any one time during execution.
34  */
35 struct FrontendId {
36 	const uint adapter_number;
37 	const uint frontend_number;
38 
39 	this(const uint a_n, const uint f_n) {
40 		adapter_number = a_n;
41 		frontend_number = f_n;
42 	}
43 }
44 
45 /**
46  * A pair (where the first item is a `FrontendId` pair)  to describe the tuning information
47  * for a given frontend when it is tuned in.
48  */
49 struct TuningId {
50 	const FrontendId frontend_id;
51 	const string channel_name;
52 
53 	this(const FrontendId f_i, const string c_n) {
54 		frontend_id = f_i;
55 		channel_name = c_n;
56 	}
57 }
58 
59 // TODO Rethink use of enforce here; what is the right way of dealing with errors?
60 // Enforcing the returned pointer to be non-null is a very blunt tool.
61 
62 /**
63  * An RAII compliant pointer to the kernel managed data relating to a frontend given a `FrontendId`.
64  *
65  * The idea is that this is a domain specific std::unique_ptr like type.
66  */
67 struct FrontendParameters_Ptr {
68   private:
69      dvb_v5_fe_parms* ptr;
70   public:
71 	@disable this(this);
72 	this(const FrontendId fei, const uint verbose = 0, const uint useLegacyCall = 0) {
73 		ptr = enforce(dvb_fe_open(fei.adapter_number, fei.frontend_number, verbose, useLegacyCall));
74 	}
75 	~this() {
76 		if (ptr !is null) {
77 			dvb_fe_close(ptr);
78 		}
79 	}
80 	auto c_ptr() { return ptr; }
81 	alias c_ptr this;
82 }
83 
84 /**
85  * An RAII compliant pointer to a `dvb_file`.
86  */
87 struct File_Ptr {
88   private:
89 	dvb_file* ptr;
90   public:
91 	@disable this(this);
92 	this(const string path, const fe_delivery_system delsys = fe_delivery_system.SYS_UNDEFINED, const dvb_file_formats format = dvb_file_formats.FILE_DVBV5) {
93 		ptr = enforce(dvb_read_file_format(toStringz(path), delsys, format));
94 	}
95 	this(dvb_file* p) { ptr = p; }
96 	~this() {
97 		if (ptr !is null) {
98 			dvb_file_free(ptr);
99 		}
100 	}
101 	bool isOpen() { return ptr !is null; }
102 	auto c_ptr() { return ptr; }
103 	alias c_ptr this;
104 };
105 
106 /**
107  * An RAII compliant DMX file descriptor.
108  */
109 struct DMX_FD {
110   private:
111 	const int fd;
112   public:
113 	@disable this(this);
114 	this(const FrontendId fei) {
115 		fd = enforce(dvb_dmx_open(fei.adapter_number, fei.frontend_number));
116 	}
117 	~this() { dvb_dmx_close(fd); }
118 	auto value() { return fd; }
119 };
120 
121 /**
122  * An RAII compliant pointer to a `dvb_v5_descriptors` object.
123  */
124 struct ScanHandler_Ptr {
125   private:
126 	dvb_v5_descriptors* ptr;
127   public:
128 	@disable this(this);
129 	this(
130 		 dvb_v5_fe_parms* frontendParameters,
131 		 dvb_entry* entry,
132 		 const int dmx_fd,
133 		 check_frontend_t check_frontend,
134 		 const uint other_nit,
135 		 const uint timeout_multiplier
136 		 ) {
137 		ptr = enforce(
138 			dvb_scan_transponder(
139 				frontendParameters,
140 				entry,
141 				cast(int)dmx_fd,
142 				check_frontend,
143 				cast(void*)null,
144 				cast(uint)other_nit,
145 				cast(uint)timeout_multiplier
146 				)
147 		);
148 	}
149 	~this() {
150 		if (ptr !is null) {
151 			dvb_scan_free_handler_table(ptr);
152 		}
153 	}
154 	auto c_ptr() { return ptr; }
155 	alias c_ptr this;
156 };
157 
158 unittest {
159 	assert(FrontendId(0, 0) == FrontendId(0, 0));
160 	assert(FrontendId(0, 0) != FrontendId(1, 0));
161 	assert(FrontendId(0, 0) != FrontendId(0, 1));
162 
163 	assert(TuningId(FrontendId(0, 0), "BBC NEWS") == TuningId(FrontendId(0, 0), "BBC NEWS"));
164 	assert(TuningId(FrontendId(0, 0), "BBC NEWS") != TuningId(FrontendId(1, 0), "BBC NEWS"));
165 	assert(TuningId(FrontendId(0, 0), "BBC NEWS") != TuningId(FrontendId(0, 1), "BBC NEWS"));
166 	assert(TuningId(FrontendId(0, 0), "BBC NEWS") != TuningId(FrontendId(0, 0), "ITV"));
167 }